/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "zlang_in.h"

int InterpretExpression_MemberOf( struct ZlangRuntime *rt , enum TokenType member_of_token_type , struct ZlangInterpretStatementSegmentContext *interp_stat_seg_ctx , struct ZlangInterpretStatementContext *interp_stat_ctx , struct ZlangObject *master_obj , struct ZlangObject **result_obj )
{
	struct ZlangTokenDataUnitHeader	*token_info1 = NULL ;
	char				*token1 = NULL ;
	struct ZlangTokenDataUnitHeader	*token_info2 = NULL ;
	char				*token2 = NULL ;
	struct ZlangObject		*prop_obj = NULL ;
	struct ZlangFunction		*func = NULL ;
	struct ZlangObject		*funcp_obj = NULL ;
	int				nret = 0 ;
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_ENTER_FUNCTION(rt)
	
	TRAVELTOKEN_AND_SAVEINFO( rt , token_info1 , token1 )
	if( token_info1->token_type == TOKEN_TYPE_TRIPLE_BACK_QUOTES_STRING ) /* ```STRING``` */
	{
		struct ZlangObject	*obj = NULL ;
		char			*str = NULL ;
		int32_t			str_len ;
		
		obj = QueryObjectByObjectName( rt , token1 , token_info1 ) ;
		if( obj == NULL )
		{
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_OBJECT_NOT_IMPORTED_OR_DECLARED , "object '%s' not imported or declared" , token1 )
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_ERROR_OBJECT_NOT_IMPORTED_OR_DECLARED;
		}
		
		if( ! IsTypeOf( rt , obj , GetStringObjectInRuntimeObjectsHeap(rt) ) )
		{
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_OBJECT_TYPE_ISNOT_STRING , "object '%s' isn't string type" , token1 )
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_ERROR_OBJECT_TYPE_ISNOT_STRING;
		}
		
		nret = CallRuntimeFunction_string_GetStringValue( rt , obj , & str , & str_len ) ;
		if( nret )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return nret;
		}
		str[str_len] = '\0' ;
		
		token1 = str ;
		goto _GOTO_AFTER_CONVERTED;
	}
	if( token_info1->token_type == TOKEN_TYPE_IDENTIFICATION ) /* func_name or prop_name in object */
	{
		QueryCharsetAliasAndChangeTokenInfo( rt , token_info1 , & token1 );
		
_GOTO_AFTER_CONVERTED :
		PEEKTOKEN( rt , token_info2 , token2 )
		if( token_info2->token_type == TOKEN_TYPE_BEGIN_OF_SUB_EXPRESSION ) /* ( */
		{
			NEXTTOKEN( rt )
			
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CALL InterpretExpression_InvokeFunction ..." )
			nret = InterpretExpression_InvokeFunction( rt , member_of_token_type , interp_stat_seg_ctx , interp_stat_ctx , master_obj , token1 , result_obj ) ;
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CALL InterpretExpression_InvokeFunction return[%d]" , nret )
			if( nret )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return nret;
			}
		}
		else
		{
			if( rt->checking_mode && ( GetObjectFunctionsEntity(master_obj) == NULL || IsTypeOf(rt,master_obj,GetZObjectInRuntimeObjectsHeap(rt)) ) )
			{
				(*result_obj) = CloneObjectInTmpStack( rt , NULL , NULL ) ;
				if( (*result_obj) == NULL )
				{
					TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CloneObjectInTmpStack failed" )
					return GetRuntimeErrorNo(rt);
				}
			}
			else
			{
				prop_obj = QueryPropertyInObjectByPropertyName( rt , master_obj , token1 ) ;
				TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS_AND_FORMAT( rt , "QueryPropertyInObjectByPropertyName prop_name[%s] return prop[%p]" , token1 , prop_obj ); }
				if( prop_obj == NULL )
				{
					func = QueryFunctionInObjectByFunctionName( rt , master_obj , token1 ) ;
					if( func == NULL )
					{
						SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_PROP_NOT_FOUND_IN_OBJECT , "property '%s' not found in object '%s'" , token1 , GetObjectName(master_obj) )
						TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
						return ZLANG_ERROR_PROP_NOT_FOUND_IN_OBJECT;
					}
					
					funcp_obj = CloneFunctionPtrObjectInTmpStack( rt , NULL ) ;
					if( funcp_obj == NULL )
						return GetRuntimeErrorNo(rt);
					
					CallRuntimeFunction_functionptr_SetObjectPtr( rt , funcp_obj , master_obj );
					CallRuntimeFunction_functionptr_SetFunctionPtr( rt , funcp_obj , func );
					
					(*result_obj) = funcp_obj ;
				}
				else
				{
					(*result_obj) = prop_obj ;
				}
			}
		}
	}
	else if( token_info1->token_type == TOKEN_TYPE_END_OF_STATEMENT ) /* ; */
	{
		if( member_of_token_type == TOKEN_TYPE_DOUBLE_DOT )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
			return ZLANG_INFO_END_OF_STATEMENT;
		}
	}
	else
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "unexpect method or property" )
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return ZLANG_ERROR_SYNTAX;
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
	
	return 0;
}

